import logger from '../utils/Logger'
import socket from '@ohos.net.socket'

const TAG = "[DlnaServiceCtrl]"

export type DlnaEventInfo = {
  Action:     string
  Content: 	  string
  Title?:     string
}

type reqMethod = {
  RType: number,
  RText: string,
}

export class DlnaServiceCtrl {
  private udp: socket.UDPSocket
  private keepaliveId: number

  constructor(address: string = '127.0.0.1', port: number = 5567) {
    this.udp = socket.constructUDPSocketInstance()
    this.keepaliveId = 0
    this.DlnaServiceConnection(address, port)
  }

  // 绑定投屏服务的UDP端口
  DlnaServiceConnection = (address: string, port: number) => {
    this.udp.bind({address: address, port: port, family: 1}, err => {
      if (err) {
        logger.info(TAG, `bind fail: ${err}, address: ${address}, port: ${port}`)
        return
      }
      logger.info(TAG, `bind success, address: ${address}, port: ${port}`)
    })
  }

  // 监听UDP连接是否正常
  Keepalive = (callback: (ok: boolean, msg: string) => void) => {
    if(this.keepaliveId == 0) {
      this.keepaliveId = setInterval(() => {
        this.udp.getState((err, data) => {
          if (err) {
            callback(false, TAG + ' get udp state fail')
          }
          if(data.isBound == false){
            callback(false, TAG + 'udp state error: ' + JSON.stringify(data))
          }
          callback(true, TAG + ' Keepalive')
        })
      }, 5000)
    }
  }

  private SendMessage = (message: reqMethod, address: string, port: number) => {
    this.udp.send({
      data: JSON.stringify(message),
      address: {
        address: address,
        port: port,
        family: 1
      }
    }, err => {
      if (err) {
        logger.info(TAG,'SendMessage Fail !');
        return;
      }
      logger.info(TAG,'SendMessage Success !');
    })
  }

  // device 投屏搜索名称，callback 操作事件
  DlnaStart = (device: string, callback: (event: DlnaEventInfo) => void) => {
    this.udp.on('message', value => {
      logger.info(TAG, "on message, message:" + value.message + ", remoteInfo:" + JSON.stringify(value.remoteInfo));
      if (value.message instanceof ArrayBuffer) {
        const uint8Array = new Uint8Array(value.message);
        let str = ByteArrayToString(uint8Array)

        // 投屏推送：{"Action": "Player", "Content": "视频地址", Title: "剧集标题"}
        // 播放指令：{"Action": "Play", "Content": ""}
        // 暂停指令：{"Action": "Pause", "Content": ""}
        // ...
        const event: DlnaEventInfo = JSON.parse(str)
        callback(event)
      }
    })

    let msg: reqMethod = { RType: 1, RText: device }
    this.SendMessage(msg, '127.0.0.1', 5566)
  }

  // 同步播放器状态，DurationTime 总时长/秒, PositionTime 当前时间/秒, Playing 是否在播放, Volume 播放器音量
  DlnaPlayerStatus = (DurationTime: number, PositionTime: number, Playing: boolean, Volume: number = 100) => {
    let data = { DurationTime: DurationTime, PositionTime: PositionTime, Playing: Playing, Volume: Volume  }
    let msg: reqMethod = { RType: 3, RText: JSON.stringify(data) }
    this.SendMessage(msg, '127.0.0.1', 5566)
  }

  // 关闭投屏广播，新设备无法搜索到投屏设备，正在投屏的不影响
  DlnaRelease = () => {
    let msg: reqMethod = { RType: 2, RText: '' }
    this.SendMessage(msg, '127.0.0.1', 5566)
  }

  // 关闭DlnaServiceCtrl，断开投屏服务的UDP端口
  Close = () => {
    if(this.keepaliveId > 0) clearInterval(this.keepaliveId)
    this.keepaliveId = 0
    this.udp.close(err => {
      if (err) {
        logger.info(TAG, 'Close Fail !')
        return;
      }
      logger.info(TAG, 'Close Success !')
    })
  }
}

let ByteArrayToString = (array: Uint8Array): string => {
  let out, i, len, c;
  let char2, char3;

  out = "";
  len = array.length;
  i = 0;
  while(i < len) {
    c = array[i++];
    switch(c >> 4) {
      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
        out += String.fromCharCode(c);
        break;
      case 12: case 13:
        char2 = array[i++];
        out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
        break;
      case 14:
        char2 = array[i++];
        char3 = array[i++];
        out += String.fromCharCode(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
        break;
    }
  }
  return out;
}

/*
import { DlnaEventInfo, DlnaServiceCtrl } from '../utils/DlnaServiceCtrl'

let dlnaCtrl = new DlnaServiceCtrl()

* 监听UDP连接是否正常
dlnaCtrl.Keepalive((ok, msg)=>{
  logger.info(TAG, msg)
  * 如果UDP连接错误，可以尝试使用DlnaServiceConnection连接
  if(!ok) dlnaCtrl.DlnaServiceConnection()
})

* 启动投屏
dlnaCtrl.DlnaStart("投屏设备名称", (res: DlnaEventInfo) => {
  // 投屏推送：{"Action": "Player", "Content": "视频地址", Title: "剧集标题"}
  // 播放指令：{"Action": "Play", "Content": ""}
  // 暂停指令：{"Action": "Pause", "Content": ""}
  // ...
  logger.info(TAG, JSON.stringify(res))
  if(res.Action == "Player") {
      // 开始播放 ...
      // 开始同步播放器状态
      dlnaCtrl.DlnaPlayerStatus(154, 12, true, 92) //参数： 总时长，已播放时长，是否在播放，播放器音量
  }

})

* 关闭投屏广播
dlnaCtrl.DlnaRelease()

* 关闭DlnaServiceCtrl，断开投屏服务的UDP端口
dlnaCtrl.Close()

*/